﻿
/** Digitalfx.tv package */
package tv.digitalfx
{
	
import pete.animation.*;
import pete.layout.*;
import pete.tools.*;

import flash.events.*;
import flash.display.*;
import flash.geom.*;
import flash.text.*;
import flash.ui.*;
import flash.utils.*;






/**
* @version
* 0.1
*
* @description 
* Singleton class to make a Launcher (i.e. Quicksilver, Launchy, etc.). It will perform as the main menu for the Digitalfx website.
* 
* @example
* -----
*/
public class Launcher extends Sprite
{
	
	
	
	
	
	// Properties
	// -----------------------------------------------------------
	
	private static var instance:Launcher = null;
	private static var allowInstantiation:Boolean = false;
	
	/**
	 * Returns the single global instance of this class.
	 */
	public static function getInstance():Launcher
	{
		if ( Launcher.instance == null )
		{
			Launcher.allowInstantiation = true;
			Launcher.instance = new Launcher();
			Launcher.allowInstantiation = false;
		}
		
		return Launcher.instance;
	}
	
	/**
	 *
	 */
	public function get currentList():Sprite
	{
		return options.currentOption.listHolder;
	}
	
	/**
	 *
	 */
	public var oldList:Sprite;
	
	/**
	 * Boolean representing wether the Launcher is active.
	 */
	public var active:Boolean = false;
	
	/**
	 * Sprite that holds the menu list options graphics.
	 */
	public var list:Sprite;
	
	/**
	 * The graphic that holds the current selection and searchbox.
	 */
	public var selBox:Sprite;
	
	/**
	 * Sprite that holds the current selections description graphic
	 */
	public var selection:Sprite;
	
	/**
	 * The data that contains all the options and their child options, and so forth.
	 */
	public var options:Option;
	
	/**
	 * Insance of the mover class to use for animations.
	 */
	public var mover:Mover;
	
	/**
	 * Used for dynamic vertical positioning of the menu list options.
	 */
	public var spacer:Shape;
	
	/**
	 * Vertical spacing used to seperate menu list items.
	 */
	public var spacing:Number = 3;
	
	/**
	 * Length of time to animate transitions.
	 */
	public var duration:Number = .15;
	
	
	
	
	
	
	// Constructor
	// -----------------------------------------------------------
	
	/**
	 * Singleton constructor. Use <code>Launcher.getInstance();</code> instead.
	 */
	public function Launcher()
	{
		if ( getQualifiedClassName( super ) == "tv.digitalfx::Launcher" )
		{
			if ( allowInstantiation )
			{		
				list = new Sprite();
				selection = new Sprite();
				drawSelBox();
				drawSpacer();
				
				addChild( list );
				addChild( selBox );
				
				mover = Mover.getInstance();
				
				addEventListener( Event.ADDED_TO_STAGE, handleStage );
			}
			else
			{
				throw new Error( "Error: Instantiation failed: Use Launcher.getInstance() instead of new Launcher()." );
			}
		}
	}
	
	
	/**
	 * Loads the data needed for the Launcher's indexing and dispay.
	 * @param xml XML to load and parse.
	 */
	public function loadXML( xml:XML ):void
	{
		options = new Option( xml );
		options.addEventListener( MouseEvent.CLICK, handleClick );
	}
	
	
	
	
	
	
	// Control Functions
	// -----------------------------------------------------------
	
	public function prevOption( animSel:Boolean = false ):void
	{
		options.previous();
			
		showDescription();
		
		placeSpacer( options.currentList.currentIndex + 1 );
		
		showList();
			
		( animSel ) ? moveSelUp() : moveListDown();
	}
	
	
	public function nextOption( animSel:Boolean = false ):void
	{
		options.next();
			
		showDescription();
		
		placeSpacer( options.currentList.currentIndex );
		
		showList();
		
		( animSel ) ? moveSelDown() : moveListUp();
	}
	
	
	public function prevList():void
	{
		oldList = currentList;
		
		options.currentOption.list.reset();
		
		if ( options.back() )
		{
			showDescription();
			
			placeSpacer( options.currentList.currentIndex );
			
			moveListRight();			
		}
		else
		{			
			options.reset();
			
			showDescription();
			
			placeSpacer();
			
			showList();
			
			moveListDown();
		}
	}
	
	
	public function nextList():void
	{
		oldList = currentList;
		
		if ( options.select() )
		{
			if (!options.currentList.isDefault)
			{
				trace( "Go to: " + options.currentList.current.title );
			}
		}
		else
		{
			showDescription();
			
			placeSpacer();
			
			moveListLeft();
		}
	}
	
	
	public function reset ():void
	{
		options.reset();
		
		options.currentList.reset();
		
		showDescription();
		
		placeSpacer();
		
		showList();
		
		initPosition();
		
		moveListDown();
	}
	
	
	
	
	
	
	// Animation Functions
	// -----------------------------------------------------------
	
	private function moveSelDown():void
	{	
		var s:*		= this;
		var t:*		= currentList;
		
		var c:Sprite		= options.currentList.current.optGraphic;
		var b:Rectangle 	= c.getBounds( this.stage );
		
		var sY:Number 	= b.bottom - selBox.height;
		var tY:Number		= - spacer.y;
		
		mover.tween( s, {"y": sY}, duration);
		mover.tween( t, {"y": tY}, duration);
	}
	
	
	private function moveSelUp():void
	{
		var s:*		= this;
		var t:*		= currentList;
		
		var c:Sprite		= options.currentList.current.optGraphic;
		var b:Rectangle 	= c.getBounds( this.stage );
		var tB:Rectangle	= spacer.getBounds( this );
		
		var sY:Number 	= b.top;
		var tY:Number 	= selBox.height - spacer.y - spacer.height;
		
		mover.tween( s, {"y": sY}, duration);
		mover.tween( t, {"y": tY}, duration);
	}
	
	
	private function moveListDown():void
	{
		var t:* 	= list.getChildAt( 0 );
		var tY:Number = selBox.y + selBox.height - spacer.y - spacer.height;
		
		mover.tween( t, {"y": tY}, duration );
	}
	
	
	private function moveListUp():void
	{
		var t:* 	= list.getChildAt( 0 );
		var tY:Number = selBox.y - spacer.y;
		
		mover.tween( t, {"y": tY}, duration );
	}
	
	
	private function moveListLeft():void
	{
		active = false;
		
		currentList.x = selBox.width;
		currentList.y = selBox.height - spacer.y - spacer.height;
		
		list.addChild( currentList );
		
		var otX:Number = oldList.x - selBox.width;
		var ctX:Number = currentList.x - selBox.width;
		
		mover.tween( oldList, {"x": otX}, duration);
		mover.tween( currentList, {"x": ctX}, duration);
		
		oldList.addEventListener( MoverEvent.MOTION_COMPLETE, handleListTrans );
	}
	
	
	private function moveListRight():void
	{
		active = false;
		
		currentList.x = -selBox.width;
		currentList.y = -spacer.y;
		
		list.addChild( currentList );
		
		var otX:Number = oldList.x + selBox.width;
		var ctX:Number = currentList.x + selBox.width;
		
		mover.tween( oldList, {"x": otX}, duration);
		mover.tween( currentList, {"x": ctX}, duration);
		
		oldList.addEventListener( MoverEvent.MOTION_COMPLETE, handleListTrans );
	}
	
	
	private function handleListTrans( e:MoverEvent ):void
	{
		active = true;
		
		list.removeChild( oldList );
		
		oldList.removeEventListener( MoverEvent.MOTION_COMPLETE, handleListTrans );
	}
	
	
	private function showDescription():void
	{
		var d:*;
		
		if ( options.currentList.isDefault )
		{
			d = selection.addChild( options.currentOption.descGraphic );
		}
		else
		{
			d = selection.addChild( options.currentList.current.descGraphic );
		}
		
		var c:* = selection.getChildAt( 0 );
		
		if ( c != d )
		{
			removeChildren( selection );
			selection.addChild( d );
		}
	}
	
	
	private function showList():void
	{
		currentList.x = 0;
		
		if ( list.numChildren == 1 )
		{
			var c:* = list.getChildAt( 0 );
			
			if ( c != currentList );
			{
				removeChildren( list );
				list.addChild( currentList );
			}
		}
		else
		{
			list.addChild( currentList );
		}
	}
	
	
	private function toggleLauncher():void
	{
		if ( active )
		{
			this.visible = false;
			active = false;
		}
		else
		{
			this.visible = true;
			active = true;
		}
	}
	
	
	
	
	
	
	// Layout Functions
	// -----------------------------------------------------------
	
	private function initPosition():void
	{
		Align.centerHorizontal( this );
		this.y = (stage.stageHeight / 2) - selBox.height;
		
		Align.centerHorizontalTo( list, selBox );
	}
	
	
	private function placeSpacer( i:int = 0 ):void
	{
		currentList.addChild( spacer );
		
		var order:Array = options.currentList.getByProperty( "optGraphic" );
		order.splice( i, 0, spacer );
		order[0].y = 0;
		
		Distribute.vertical( order, spacing );
	}
	
	
	
	
	
	
	// Drawing Functions
	// -----------------------------------------------------------
	
	private function drawSelBox():void
	{
		selBox = new Sprite ();
		selBox.graphics.lineStyle( 1 );
		selBox.graphics.beginFill( 0xffffff, 1 );
		selBox.graphics.drawRect( 0, 0, 200, 70 );
		
		selBox.addChild( selection );
	}
	
	
	private function drawSpacer():void
	{
		spacer = new Shape();
		spacer.graphics.beginFill( 0xff0000, 0 );
		spacer.graphics.drawRect( 0, 0, 100, 37 );
	}
	
	
	
	
	
	
	// Event Handlers
	// -----------------------------------------------------------
	
	private function handleStage( e:Event ):void
	{
		showDescription();
		
		placeSpacer();
		
		showList();
		
		initPosition();
		
		toggleLauncher();
		
		moveListDown();
		
		stage.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyboard );
	}
	
	
	private function handleKeyboard( e:KeyboardEvent ):void
	{
		if ( active )
		{
			switch ( e.keyCode )
			{
				case Keyboard.ENTER:
				case Keyboard.RIGHT:
				nextList();
				break;
				
				case Keyboard.UP:
				prevOption();
				break;
				
				case Keyboard.DOWN:
				nextOption();
				break;
				
				case Keyboard.LEFT:
				prevList();
				break;
				
				case Keyboard.ESCAPE:
				reset();
				break;
				
				default:
				break;
			}
		}
		
		if ( e.keyCode == Keyboard.SPACE )
		{
			toggleLauncher();
		}
	}
	
	
	private function handleClick( e:MouseEvent ):void
	{
		trace( e.target.title );
	}
	
}

}